import {
  BaseSymbol,
  FunctionArgument,
  FunctionSymbol,
  IntegerSymbol,
  RealSymbol,
  StringSymbol,
  VectorSymbol,
} from "./PL00Symbols";

/**
 * 根据提供的基本输入和输出函数返回内置函数
 * @param output 输出函数
 * @param input 输入函数
 * @returns 内置函数数组字典
 */
function BuiltinsFactory(
  output: Function,
  input: Function
): { [name: string]: FunctionSymbol[] } {
  /**
   * 基本输出函数
   * @param symbol 待输出的符号
   * @returns 返回输出的符号
   */
  function write(symbol: BaseSymbol): BaseSymbol {
    output(symbol.value);
    return symbol;
  }
  /**
   * 输入整型
   * @param symbol 待输入的整型符号
   */
  function readInteger(symbol: IntegerSymbol) {
    symbol.value = parseInt(input());
  }
  /**
   * 输入实型
   * @param symbol 待输入的实型符号
   */
  function readReal(symbol: RealSymbol) {
    symbol.value = parseFloat(input());
  }
  /**
   * 输入字符串
   * @param symbol 待输入的字符串符号
   */
  function readString(symbol: StringSymbol) {
    symbol.value = input();
  }
  // 整理
  const functions: { [name: string]: FunctionSymbol[] } = {
    write: [
      new FunctionSymbol(write, "Integer", [
        new FunctionArgument("_", "Integer"),
      ]),
      new FunctionSymbol(write, "Real", [new FunctionArgument("_", "Real")]),
      new FunctionSymbol(write, "String", [
        new FunctionArgument("_", "String"),
      ]),
    ],
    read: [
      new FunctionSymbol(readInteger, "Integer", [
        new FunctionArgument("_", "Integer"),
      ]),
      new FunctionSymbol(readReal, "Real", [new FunctionArgument("_", "Real")]),
      new FunctionSymbol(readString, "String", [
        new FunctionArgument("_", "String"),
      ]),
    ],
    length: [
      new FunctionSymbol(
        (vec: VectorSymbol) => new IntegerSymbol(vec.value.length),
        "Integer",
        [new FunctionArgument("_", "Any")]
      ),
      new FunctionSymbol(
        (str: StringSymbol) => new IntegerSymbol(str.value.length),
        "Integer",
        [new FunctionArgument("_", "String")]
      ),
    ],
    toStr: [
      new FunctionSymbol(
        (x) => new StringSymbol(x.value.toString()),
        "String",
        [new FunctionArgument("_", "Integer")]
      ),
      new FunctionSymbol(
        (x) => new StringSymbol(x.value.toString()),
        "String",
        [new FunctionArgument("_", "Real")]
      ),
      new FunctionSymbol(
        (x) => new StringSymbol(x.value.toString()),
        "String",
        [new FunctionArgument("_", "String")]
      ),
      new FunctionSymbol(
        (x) => new StringSymbol(x.value.toString()),
        "String",
        [new FunctionArgument("_", "Vector")]
      ),
    ],
  };
  return functions;
}

export default BuiltinsFactory;
